/*
 * Copyright 2022-2023 the original author(https://github.com/wj596)
 * 
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * </p>
 */
package org.jsets.fastboot.flowable.service.impl;

import java.util.List;
import javax.transaction.Transactional;
import org.flowable.engine.IdentityService;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.GroupQuery;
import org.flowable.idm.api.User;
import org.flowable.idm.api.UserQuery;
import org.jsets.fastboot.flowable.model.dto.FlowUser;
import org.jsets.fastboot.flowable.model.dto.FlowUserGroup;
import org.jsets.fastboot.flowable.model.dto.FlowUserGroupQuery;
import org.jsets.fastboot.flowable.model.dto.FlowUserQuery;
import org.jsets.fastboot.flowable.service.IFlowIdentityService;
import org.jsets.fastboot.util.CollectionUtils;
import org.jsets.fastboot.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;

/**
 * @author wangjie (https://github.com/wj596)
 * @date 2021.06.25 11:23
 */
@Service
public class FlowIdentityService implements IFlowIdentityService {
	
	@Autowired
	private FlowEngineService flowEngine;
	
	@Override
	@Transactional(rollbackOn = Exception.class)
	public boolean saveUser(FlowUser flowUser) {
		User user = this.flowEngine.getIdentityService().newUser(flowUser.getId());
		user.setDisplayName(flowUser.getName());
		this.flowEngine.getIdentityService().saveUser(user);

		if (CollectionUtils.notEmpty(flowUser.getGroups())) {
			flowUser.getGroups().forEach(g -> {
				this.flowEngine.getIdentityService().createMembership(flowUser.getId(), g);
			});
		}

		return true;
	}

	@Override
	@Transactional(rollbackOn = Exception.class)
	public boolean deleteUser(String account) {
		List<Group> groups =this.flowEngine.getIdentityService().createGroupQuery().groupMember(account).list();
		if(CollectionUtils.notEmpty(groups)) {
			groups.forEach(t->{
				this.flowEngine.getIdentityService().deleteMembership(account, t.getId());
			});
		}
		this.flowEngine.getIdentityService().deleteUser(account);
		return true;
	}

	@Override
	@Transactional(rollbackOn = Exception.class)
	public boolean saveGroup(FlowUserGroup entity) {
		//删除group的membership
		IdentityService identityService = this.flowEngine.getIdentityService();
		List<User> binds =identityService.createUserQuery().memberOfGroup(entity.getId()).list();
		for (User user : binds) {
			identityService.deleteMembership(user.getId(), entity.getId());
		}
		
		Group group = this.flowEngine.getIdentityService().newGroup(entity.getId());
		group.setName(entity.getName());
		group.setType(entity.getId());
		this.flowEngine.getIdentityService().saveGroup(group);
		
		//保存group的membership
		if(CollectionUtils.notEmpty(entity.getUserIds())) {
			for (String id : entity.getUserIds()) {
				identityService.createMembership(id, entity.getId());
			}
		}

		return true;
	}

	@Override
	@Transactional(rollbackOn = Exception.class)
	public boolean deleteGroup(String groupId) {
		//删除group的membership
		IdentityService identityService = this.flowEngine.getIdentityService();
		List<User> binds =identityService.createUserQuery().memberOfGroup(groupId).list();
		for (User user : binds) {
			identityService.deleteMembership(user.getId(), groupId);
		}
		this.flowEngine.getIdentityService().deleteGroup(groupId);
		return true;
	}

	@Override
	public Page<FlowUserGroup> selectFlowGroupPage(FlowUserGroupQuery criteria) {
		GroupQuery query = this.flowEngine.getIdentityService().createGroupQuery().orderByGroupId().asc();

		if (StringUtils.notEmpty(criteria.getName())) {
			query.groupName(criteria.getName());
		}
		if (StringUtils.notEmpty(criteria.getType())) {
			query.groupType(criteria.getType());
		}

		Page<FlowUserGroup> page = new Page<FlowUserGroup>();
		page.setTotal(query.count());
		List<FlowUserGroup> records = Lists.newArrayList();
		List<Group> ls = query.listPage(criteria.getOffset(), criteria.getSize());
		ls.forEach(t -> {
			FlowUserGroup g = new FlowUserGroup();
			g.setId(t.getId());
			g.setName(t.getName());
			g.setType(t.getType());
			List<User> members = this.flowEngine
				.getIdentityService()
				.createUserQuery()
				.memberOfGroup(t.getId())
				.list();
			g.setAllUserNameCommaSplit(StringUtils.join(members, it->it.getDisplayName()));
			records.add(g);
		});
		page.setRecords(records);
		return page;
	}

	@Override
	public List<FlowUserGroup> selectFlowGroupList(FlowUserGroupQuery criteria) {
		GroupQuery query = this.flowEngine.getIdentityService().createGroupQuery().orderByGroupId().asc();

		if (StringUtils.notEmpty(criteria.getName())) {
			query.groupName(criteria.getName());
		}
		if (StringUtils.notEmpty(criteria.getType())) {
			query.groupType(criteria.getType());
		}

		List<FlowUserGroup> records = Lists.newArrayList();
		List<Group> ls = query.list();
		ls.forEach(t -> {
			FlowUserGroup g = new FlowUserGroup();
			g.setId(t.getId());
			g.setName(t.getName());
			g.setType(t.getType());
			List<User> members = this.flowEngine
				.getIdentityService()
				.createUserQuery()
				.memberOfGroup(t.getId())
				.list();
			g.setAllUserNameCommaSplit(StringUtils.join(members, it->it.getDisplayName()));
			records.add(g);
		});
		return records;
	}
	
	@Override
	public FlowUserGroup getGroupById(String groupId) {
		Group group = this.flowEngine.getIdentityService().createGroupQuery().groupId(groupId).singleResult();
		FlowUserGroup fug = new FlowUserGroup();
		fug.setId(group.getId());
		fug.setName(group.getName());
		fug.setType(group.getType());
		fug.setUsers(this.selectUserByGroup(groupId));
		return fug;
	}

	@Override
	public List<FlowUser> selectUserByGroup(String groupId) {
		List<FlowUser> users = Lists.newArrayList();
		this.flowEngine
			.getIdentityService()
			.createUserQuery()
			.memberOfGroup(groupId)
			.list()
			.forEach(t->{
				FlowUser fu = new FlowUser();
				fu.setId(t.getId());
				fu.setName(t.getFirstName());
				users.add(fu);
			});
		return users;
	}
	
	@Override
	public Long getUserCountByGroup(String groupId) {
		return this.flowEngine
			.getIdentityService()
			.createUserQuery()
			.memberOfGroup(groupId)
			.count();
	}

	@Override
	public Page<FlowUser> selectFlowUserPage(FlowUserQuery criteria) {
		UserQuery query = this.flowEngine.getIdentityService().createUserQuery().orderByUserId().asc();

		if (StringUtils.notEmpty(criteria.getAccount())) {
			query.userId(criteria.getAccount());
		}
		if (StringUtils.notEmpty(criteria.getName())) {
			query.userDisplayNameLike(criteria.getName());
		}

		Page<FlowUser> page = new Page<FlowUser>();
		page.setTotal(query.count());
		List<FlowUser> records = Lists.newArrayList();
		List<User> ls = query.listPage(criteria.getOffset(), criteria.getSize());
		ls.forEach(t -> {
			FlowUser g = new FlowUser();
			g.setId(t.getId());
			g.setName(t.getDisplayName());
			records.add(g);
		});
		page.setRecords(records);
		return page;
	}

}